package springmvc.components.adaptor;

import server.request.HttpRequest;
import server.response.HttpResponse;
import springmvc.annotation.RequestParam;
import springmvc.components.mapping.HandlerMapping;
import springmvc.utils.ParseStringContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author cg
 * @date 2023/6/16 16:06
 */
public class HandlerAdaptor {
    /**
     * 判断当前handlerMapping是否是自己能处理的，本文只有一种，所以必定匹配
     * @param handlerMapping
     * @return
     */
    public boolean support(Object handlerMapping) {
        return handlerMapping instanceof HandlerMapping;
    }

    /**
     * @param request http请求
     * @param response http响应
     * @param handler 请求映射器
     * @return
     */
    public Object handle(HttpRequest request, HttpResponse response, Object handler) throws InvocationTargetException, IllegalAccessException {
        HandlerMapping handlerMapping = (HandlerMapping) handler;
        Object controller = handlerMapping.getController();
        Method method = handlerMapping.getMethod();
        //解析映射方法的参数
        List<MethodParameter> methodParameters = resolveMethodParameter(method);
        Map<String, String> parameterMap = request.getParameterMap();
        Object[] args = handlePathParameter(parameterMap, methodParameters, request, response);
        return method.invoke(controller, args);
    }

    /**
     * 将请求路径的参数一一对应到方法的参数种
     * @param parameterMap 请求路径参数
     * @param methodParameters 映射方法参数
     * @return 转换后的方法参数之列表
     */
    private Object[] handlePathParameter(Map<String, String> parameterMap, List<MethodParameter> methodParameters,HttpRequest request , HttpResponse response) {
        Object[] args = new Object[methodParameters.size()];
        int idx = 0;
        for (MethodParameter methodParameter : methodParameters) {
            Class<?> fieldClazz = methodParameter.getClazz();
            //如果是Http的请求，则直接填充
            if (HttpRequest.class.isAssignableFrom(fieldClazz)) {
                args[idx] = request;
            } else if (HttpResponse.class.isAssignableFrom(fieldClazz)) {
                args[idx] = response;
            } else {
                String fieldName = methodParameter.getFieldName();
                //从请求路径中找到对应的值
                String value = parameterMap.get(fieldName);
                //处理空指针
                if (value == null) {
                    //如果是POST请求则继续尝试填充自定义类
                    Object o = null;
                    if (request.getMethod().equals("POST")){
                        o = ParseStringContext.objectParseString(fieldClazz, request.getRequestBodyMap());
                    }
                    if (o != null) {
                        args[idx] = o;
                    }
                }else {
                    args[idx] = ParseStringContext.parse(fieldClazz, value);
                }
            }
            idx++;
        }
        return args;
    }

    /**
     * 按顺序解析方法上的参数列表
     * @param method 映射方法
     * @return
     */
    private List<MethodParameter> resolveMethodParameter(Method method) {
        List<MethodParameter> methodParameter = new CopyOnWriteArrayList<>();
        //获取method的参数列表
        for (Parameter parameter : method.getParameters()) {
            String fileName = parameter.getName();
            boolean require = true;
            RequestParam requestParam = parameter.getAnnotation(RequestParam.class);
            if (requestParam != null) {
                fileName = requestParam.value();
                require = requestParam.require();
            }
            methodParameter.add(new MethodParameter(parameter.getType(), fileName, require));
        }
        return methodParameter;
    }
}
